﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using eLoop;
using eNets.IO;

namespace eNets.CBK.Sockets;

abstract class ASocketOper : ISocketArgsCompleted, IDisposable
{
    public ASocketOper(Socket socket, ITaskScheduler scheduler, SocketCompletedDelegate notify)
    {
        this.socket = socket;
        this.args = new SocketArgs(scheduler, this);
        this.notify = notify;
    }
    
    private Socket socket;
    private SocketArgs args;
    private SocketCompletedDelegate notify;
    
    public EndPoint RemoteAddress
    {
        get { return this.args.RemoteEndPoint; }
        set { this.args.RemoteEndPoint = value; }
    }

    public object UserToken
    {
        get { return this.args.UserToken; }
        set { this.args.UserToken = value; }
    }

    public byte ValueToken
    {
        get { return this.args.ValueToken; }
        set { this.args.ValueToken = value; }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    protected void SetArgsBuffer(Memory<byte> memory)
    {
#if NETSTANDARD2_1
        var segment = memory.GetArray();
        this.args.SetBuffer(segment.Array, segment.Offset, segment.Count);
#elif NET5_0
        this.args.SetBuffer(memory);
#endif
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    protected void SetArgsBuffer(IList<ArraySegment<byte>> segments)
    {
        this.args.BufferList = segments;
    }


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    protected void SocketOperationCombineAsync()
    {
        if (!this.SocketOperationAsync(this.socket, this.args))
        {
            this.SocketAsyncEventCompleteNotify(this.args);
        }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    protected abstract bool SocketOperationAsync(Socket socket, SocketArgs args);

    void ISocketArgsCompleted.OnComplete(SocketArgs args)
    {
        this.SocketAsyncEventCompleteNotify(args);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void SocketAsyncEventCompleteNotify(SocketArgs e)
    {
        this.notify(new SocketResult(e));
    }
    
    
    public void Dispose()
    {
        if (this.args != null)
        {
            this.args.Dispose();
            this.args = null;
        }
    }
}